////////////////////////////////////////////////////////////////////////////
//
//  CryEngine Source File.
//  Copyright (C), Crytek, 2010.
// -------------------------------------------------------------------------
//  File name:   CryGameSpyLobby.h
//  Version:     v1.00
//  Created:     29/03/2010 by Paul Mikell.
//  Description: CCryGameSpyLobby class definition
// -------------------------------------------------------------------------
//  History:
//
////////////////////////////////////////////////////////////////////////////


#ifndef __CRYGAMESPYLOBBY_H__

#define __CRYGAMESPYLOBBY_H__

#if _MSC_VER > 1000
#pragma once
#endif

#include "Lobby/CryLobby.h"

#if USE_CRYLOBBY_GAMESPY

#include "CryLobbyEvent.h"
#include "Lobby/CryTCPServiceFactory.h"
#include "Lobby/GameSpy/ICryGameSpyLobbyComponent.h"
#include "Lobby/GameSpy/CryGameSpyMatchMaking.h"
#include "Lobby/GameSpy/CryGameSpyVoice.h"
#include "Lobby/GameSpy/CryGameSpyStats.h"
#include "Lobby/GameSpy/CryGameSpyFriends.h"
#include "Lobby/GameSpy/CryGameSpyFriendsManagement.h"
#include "Lobby/GameSpy/CryGameSpyLobbyUI.h"
#include "Lobby/GameSpy/CryGameSpyDLCStore.h"
#include "Gamespy2.11.00/Source/Peer/peer.h"
#include "Gamespy2.11.00/Source/gp/gp.h"
#include "Gamespy2.11.00/Source/qr2/qr2.h"

#define GAMESPY_MAX_SECRET_KEY_LEN 64
#define GAMESPY_MAX_VERSION_STRING_LEN	32

enum CryGameSpyLobbyPacketType
{
	eGameSpyPT_SessionRequestJoinResult = eLobbyPT_SessionRequestJoinResult,

	eGameSpyPT_MM_RequestServerData = CRYONLINELOBBY_PACKET_START,
	eGameSpyPT_MM_ServerData,
	eGameSpyPT_SessionRequestJoin,
	eGameSpyPT_SessionAddRemoteConnections,
	eGameSpyPT_HostMigrationStart,
	eGameSpyPT_HostMigrationServer,
	eGameSpyPT_HostMigrationClient,
	eGameSpyPT_UserData,
	eGameSpyPT_Voice,
	eGameSpyPT_VoiceMicrophoneNotification,
	eGameSpyPT_SessionPing,
	eGameSpyPT_SessionPong,
	eGameSpyPT_SessionRequestInfo,
	eGameSpyPT_SessionRequestInfoResponse,
	eGameSpyPT_CDKeyChallenge,
	eGameSpyPT_CDKeyResponse,
	eGameSpyPT_PropagatePassword,

	eGameSpyPT_EndType
};

enum ECryGameSpyObjectState
{
	eCGSOS_NotInitialized,		// For all GameSpy objects
	eCGSOS_Initializing,			// For all GameSpy objects
	eCGSOS_Initialized,				// For all GameSpy objects
	eCGSOS_Connecting,				// For all except core and availability check
	eCGSOS_Connected					// For all except core and availability check
};


typedef void ( *peerLeaveRoomCallback )( void* pArg );

class CCryGameSpyLobbyService: public CCryLobbyService, public ICryGameSpyLobbyComponent
{
public:

	// Default maximum simultaneous updates.
	static const uint32			k_defaultMaxUpdates = 20;

	// Description:
	//	 Default constructor for CCryGameSpyLobbyService.
	 CCryGameSpyLobbyService(CCryLobby* pLobby, ECryLobbyService service);

	// Description:
	//	 Destructor for CCryGameSpyLobbyService.
	virtual ~CCryGameSpyLobbyService();

	// Description:
	//	 Initialise the CCryGameSpyLobbyService.
	// Arguments:
	//	 cb - callback
	//	 pLobby - lobby
	//	 service - service type
	// Return:
	//	 Error code.
	virtual ECryLobbyError Initialise( ECryLobbyServiceFeatures features, CryLobbyServiceCallback pCB );

	// Description:
	//	 Terminate the CCryGameSpyLobbyService.
	// Arguments:
	//	 cb - callback
	//	 pLobby - lobby
	//	 service - service type
	// Return:
	//	 Error code.
	virtual ECryLobbyError Terminate( ECryLobbyServiceFeatures features, CryLobbyServiceCallback pCB );

	// Description:
	//	 Tick the CCryGameSpyLobbyService.
	// Arguments:
	//	 tv - time
	virtual void Tick( CTimeValue tv );

	//////////////////////////////////////////////////////////
	// ICryLobbyService implementation
	//////////////////////////////////////////////////////////

	// Description:
	//	 Get matchmaking.
	// Return:
	//   Pointer to matchmaking.
	virtual ICryMatchMaking* GetMatchMaking();

	// Description:
	//	 Get voice.
	// Return:
	//   Pointer to voice.
	virtual ICryVoice* GetVoice();

	// Description:
	//	 Get stats.
	// Return:
	//   Pointer to stats.
	virtual ICryStats* GetStats();

	// Description:
	//	 Get lobby UI.
	// Return:
	//   Pointer to lobby UI.
	virtual ICryLobbyUI* GetLobbyUI();

	// Description:
	//	 Get friends.
	// Return:
	//   Pointer to friends.
	virtual ICryFriends* GetFriends();

	// Description:
	//	 Get friends management.
	// Return:
	//   Pointer to friends management.
	virtual ICryFriendsManagement* GetFriendsManagement();

	virtual ICryReward*	GetReward();

	virtual ICryDLCStore*	GetDLCStore();

	// Description:
	//	 Get the user id of a user signed in to this service locally.
	// Arguments:
	//	 user - The pad number of the local user.
	// Return:
	//   The CryUserID of the user.
	virtual	CryUserID GetUserID( uint32 user );

	virtual ECryLobbyError GetUserPrivileges(uint32 user, CryLobbyTaskID* pTaskID, CryLobbyPrivilegeCallback pCB, void* pCBArg);
	virtual	ECryLobbyError GetUserCredentials( uint32 user, CryLobbyTaskID* pTaskID, CryLobbyGetUserCredentialsCallback pCB, void* pCBArg );
	virtual ECryLobbyError UserSignOut( uint32 user, CryLobbyTaskID* pTaskID, CryLobbyOnlineStateCallback pCb, void* pCbArg );
	virtual ECryLobbyError CheckProfanity( const char* const pString, CryLobbyTaskID* pTaskID, CryLobbyCheckProfanityCallback pCb, void* pCbArg );

	virtual ECryLobbyError GetSystemTime(uint32 user, SCrySystemTime* pSystemTime);
	//////////////////////////////////////////////////////////

	virtual void OnGameSpyObjectAvailable( EGameSpyObjectBit object );
	virtual void OnGameSpyObjectUnavailable( EGameSpyObjectBit object );
	virtual void OnGameSpyObjectCantMakeAvailable( EGameSpyObjectBit object );
	uint32 GetAvailableGameSpyObjects();

	// Description:
	//	 Called when a packet is received.
	// Arguments:
	//	 addr - address
	//	 pData - data
	//	 length - length
	virtual void OnPacket( const TNetAddress& addr, CCryLobbyPacket* pPacket );

	// Description:
	//	 Called on error.
	// Arguments:
	//	 addr - address
	//	 error - error
	//	 sendID - send ID
	virtual void OnError( const TNetAddress& addr, ESocketError error, CryLobbySendID sendID );

	// Description:
	//	 Called on error.
	// Arguments:
	//	 addr - address
	//	 error - error
	virtual void OnError( const TNetAddress& addr, ESocketError error );

	// Description:
	//	 Empty implementation of OnSendComplete for ICryLobbyService that doesn't share
	//	 socket with ICryLobby.
	// Arguments:
	//	 addr - address
	//	 sendID - send ID
	virtual void OnSendComplete( const TNetAddress& addr, CryLobbySendID sendID );

	virtual void GetSocketPorts(uint16& connectPort,uint16& listenPort);

	// Description:
	//	 Get local user name.
	// Return:
	//	 Local user name.
	const char* GetLocalUserName();

	void SetNeedAvailabilityCheck( bool needAvailabilityCheck );
	void SetNeedAuthService( bool needAuthService );

	void SetNeedGPConnection( bool needGPConnection );

	void SetNeedPeer( bool needPeer );
	void SetNeedCDKey( bool needCDKey );

	bool HaveGPConnection();
	const GPConnection* const GetGPConnection();

	bool HavePeer();

	// Description:
	//	 Refresh the group rooms.
	// Return:
	//	 Error code.
	ECryLobbyError PeerRefreshGroupRooms();

	// Description:
	//	 Join the title room.
	// Arguments:
	//	 cb - callback
	//	 pParam - callback user data
	void PeerJoinTitleRoom( peerJoinRoomCallback cb, void* pParam );

	// Description:
	//	 Leave the title room.
	void PeerLeaveTitleRoom();

	// Description:
	//	 Join a group room.
	// Arguments:
	//	 groupID - group ID
	//	 cb - callback
	//	 pParam - callback user data
	void PeerJoinGroupRoom( int groupID, peerJoinRoomCallback cb, void* pParam  );

	// Description:
	//	 Leave the current group room.
	void PeerLeaveGroupRoom();

	// Description:
	//	 Create a staging room.
	// Arguments:
	//	 pName - name of room
	//	 maxPlayers - maximum number of players
	//	 pPassword - password
	//	 cb - callback
	//	 pParam - callback parameter
	void PeerCreateStagingRoom( const gsi_char* pName, int maxPlayers, const gsi_char* pPassword, peerJoinRoomCallback cb, void* pParam );

	// Description:
	//	 Join a staging room.
	// Arguments:
	//	 server - server
	//	 pPassword - password
	//	 cb - callback
	//	 pParam - callback parameter
	void PeerJoinStagingRoom( SBServer server, const gsi_char* pPassword, peerJoinRoomCallback cb, void* pParam );

	// Description:
	//	 Leave the current staging room.
	void PeerLeaveStagingRoom( peerLeaveRoomCallback cb, void* pParam );

	// Description:
	//	 Start listing games.
	// Arguments:
	//	 pFields - fields
	//	 numFields - number of fields
	//	 pFilter - filter
	//	 callback - callback
	//	 pParam - callback parameter
	// Return:
	//	 eCLE_Success or an error code
	ECryLobbyError PeerStartListingGames( const unsigned char* pFields, int numFields, const gsi_char* pFilter, peerListingGamesCallback callback, void* pParam );

	void PeerStopListingGames();

	void PeerUTMStagingRoom( const gsi_char* pCmd, const gsi_char* pParams );

	void PeerUTMPlayer( const gsi_char* pNick, const gsi_char* pCmd, const gsi_char* pParams );

	void PeerStartGame();
	void PeerStopGame();
	void PeerSendNatNegotiateCookie(uint32 ip, uint16 port, uint32 cookie);
	void PeerStateChanged();
	void PeerSetStagingRoomMaxPlayers( uint32 maxPlayers );
	bool PeerIsInCorrectStagingRoom( SCryGameSpyRemoteConnectionID* id );

	// Description:
	//	 Shut down the peer.
	void PeerShutdown();

	GPResult GPGetInfo( GPProfile profile, GPEnum checkCache, GPCallback callback, void* pParam );
	void GPSetStatus( GPEnum status );
	void GPSetStatusString( const char* pStatusString );
	void GPSetLocationString( const char* pLocationString );

	// Description:
	//	 Do we have the local user name yet?
	// Return:
	//	 True if we have the public address, otherwise false.
	bool HasLocalUserName();

	// Description:
	//	 Do we have the public address yet?
	// Return:
	//	 True if we have the public address, otherwise false.
	bool HasPublicAddress();

	// Description:
	//	 Get the public IP address.
	// Return:
	//	 The public IP address.
	uint32 GetPublicIP();

	// Description:
	//	 Get the public port.
	// Return:
	//	 The public port.

	uint16 GetPublicPort();
	uint32 GetPrivateIP();
	uint16 GetPrivatePort();

	uint32 GetGameID();

	GPProfile GetProfileID();

	virtual void OnInternalSocketChanged( IDatagramSocketPtr pSocket );

	static ECryLobbyError GetErrorFromGameSpy(GPResult error, GPConnection* pGPConnection);

	void InviteAccepted(uint32 user, CrySessionID id);
	void InviteAcceptedAcknowledgement(int cookie);

	GSLoginCertificate*	AuthServiceGetCertificate();
	GSLoginPrivateData* AuthServiceGetPrivateData();
	void AuthServiceInvalidateCertificate();
	void AuthServiceCheckCertificate();

	static void LocalCDKeyAuthCallback( int gameid, int localid, int authenticated, char* pErrMsg, void* pParam );
	static void LocalCDKeyReauthCallback( int gameid, int localid, int hint, char* pChallenge, void* pParam );

	// Description:
	//	 Get GameSpy matchmaking.
	// Return:
	//	 GameSpy matchmaking.
	CCryGameSpyMatchMaking*	GetGameSpyMatchMaking();

private:

	enum ETask
	{
		eT_UserSignOut = eT_LobbyPlatformSpecificTask,
		eT_GetUserCredentials,
		eT_CheckProfanity
	};

	enum ETaskState
	{
		eTS_NotStarted,
		eTS_InProgress,
		eTS_Succeeded,
		eTS_CannotStart,
		eTS_Failed
	};

	enum ERoomJoinState
	{
		eRJS_NotJoined,
		eRJS_JoinInProgress,
		eRJS_Joined
	};

	enum EReportingState
	{
		eRS_Inactive,
		eRS_Server,
		eRS_StagingRoomHost,
		eRS_StagingRoomPeer
	};

	struct SGroupRoom
	{
		int											m_id;
		SBServer								m_server;
	};

	enum ERoomOpType
	{
		eROT_Create,
		eROT_Join,
		eROT_Leave,
		eROT_Invalid
	};

	struct SRoomOp: public CMultiThreadRefCount
	{
		SRoomOp()
		: CMultiThreadRefCount(),
			m_opType( eROT_Invalid ),
			m_roomType( NumRooms ),
			m_state( eTS_NotStarted ),
			m_cb( NULL ),
			m_pParam( NULL )
		{
		};

		ERoomOpType						m_opType;
		RoomType							m_roomType;
		ETaskState						m_state;
		void*									m_cb;
		void*									m_pParam;
	};

	typedef _smart_ptr<SRoomOp>	SRoomOpPtr;

	struct SJoinGroupRoomOp: public SRoomOp
	{
		SJoinGroupRoomOp()
		: SRoomOp(),
			m_groupID( 0 )
		{
		};

		int										m_groupID;
	};

	struct SJoinStagingRoomOp: public SRoomOp
	{
		SJoinStagingRoomOp()
		: SRoomOp(),
			m_server( NULL )
		{
			m_password[ 0 ] = '\0';
		};

		SBServer							m_server;
		char									m_password[ PEER_PASSWORD_LEN ];
	};

	struct SCreateStagingRoomOp: public SRoomOp
	{
		SCreateStagingRoomOp()
		: SRoomOp(),
			m_pName( NULL ),
			m_maxPlayers( 0 )
		{
			m_password[ 0 ] = '\0';
		};

		char*									m_pName;
		uint32								m_maxPlayers;
		char									m_password[ PEER_PASSWORD_LEN ];
	};

	enum EProfileMatchQuality
	{
		ePMQ_NoProfile = -1,
		ePMQ_AnyProfile = 0,
		ePMQ_RequiredNickProfile = 1,
		ePMQ_NamespaceAndRequiredNickProfile = 2
	};

	enum ENATDetectionState
	{
		eNDS_NotStarted,
		eNDS_InProgress,
		eNDS_Failed,
		eNDS_Succeeded,
		eNDS_Dispatched
	};

	enum EGetUserCredentialsFlag
	{
		eGUCF_StartedSearch = BIT( 0 )
	};

	void InitializeGPConnection();
	void InitializePeer();

	void GameSpyConnect();		// Kicks off login to gamespy servers
	void GameSpyDisconnect( ECryLobbyError reason );

	// Description:
	//	 Connect the peer.
	void PeerConnect();

	void StartTaskRunning(CryLobbyServiceTaskID lsTaskID);
	void StopTaskRunning(CryLobbyServiceTaskID lsTaskID);
	void EndTask(CryLobbyServiceTaskID lsTaskID);

	void StartGetUserPrivileges(CryLobbyServiceTaskID lsTaskID);
	void TickGetUserPrivileges(CryLobbyServiceTaskID lsTaskID);

	void StartGetUserCredentials( CryLobbyServiceTaskID lsTaskID );
	void TickGetUserCredentials( CryLobbyServiceTaskID lsTaskID );
	void EndGetUserCredentials( CryLobbyServiceTaskID lsTaskID );
	static void GetUserCredentialsProfileSearchCallback( GPConnection* pGPConnection, void* pArg, void* pParam );

	void StartUserSignOut( CryLobbyServiceTaskID lsTaskID );
	void TickUserSignOut( CryLobbyServiceTaskID lsTaskID );

	void StartCheckProfanity( CryLobbyServiceTaskID lsTaskID );
	void TickCheckProfanity( CryLobbyServiceTaskID lsTaskID );
	void EndCheckProfanity( CryLobbyServiceTaskID lsTaskID );
	static void CheckProfanitySakeSearchCallback( SAKE sake, SAKERequest request, SAKERequestResult result, void* pInput, void* pOutput, void* pUserData );

	void GameSpyConnectSuccess( GPConnection *pConnection );
	static void GameSpyConnectCallback( GPConnection* pConnection, void* pArg, void* pParam );
	void GameSpyCreateConnectError( GPConnection* pConnection, GPResult result, bool disconnectOnError );
	static void GameSpyCreateProfileSearchCallback( GPConnection* pConnection, void* pArg, void* pParam );
	void GameSpyCreateConnect( GPConnection* pConnection, const char* pProfileNick, GPCallback pCb );
	static void GameSpyCreateNewUserCallback( GPConnection* pConnection, void* pArg, void* pParam );
	static void GameSpyCreateConnectAnyCallback( GPConnection* pConnection, void* pArg, void* pParam );
	void GameSpyCreateReconnect( GPConnection* pConnection, GPResult result );
	static void GameSpyCreateConnectRequiredCallback( GPConnection* pConnection, void* pArg, void* pParam );
	static void GameSpyCreateCheckUserCallback( GPConnection* pConnection, void* pArg, void* pParam );
	static void GameSpyCreateNewProfileCallback( GPConnection* pConnection, void* pArg, void* pParam );
	static void GameSpyCreateRegisterUniqueNickCallback( GPConnection* pConnection, void* pArg, void* pParam );
	static void GameSpyCreateSuggestUniqueNicksDisconnectCallback( GPConnection* pConnection, void* pArg, void* pParam );
	static void GameSpyCreateSuggestUniqueNicksDontDisconnectCallback( GPConnection* pConnection, void* pArg, void* pParam );
	static void GameSpyCreateSuggestUniqueNicksCallback( GPConnection* pConnection, void* pArg, void* pParam, bool disconnect );
	static void GameSpyCreateCheckProfanityCallback( CryLobbyTaskID taskID, ECryLobbyError error, const char* pString, bool isProfanity, void* pArg );
	void GameSpyCreateRegisterUniqueNick();

	// Description:
	//	 Called when local player is disconnected.
	// Arguments:
	//	 peer - peer
	//	 pReason - reason for disconnection
	//	 pParam - user data
	static void PeerDisconnectedCallback( PEER peer, const gsi_char* pReason, void* pParam );

	// Description:
	//	 Called when chat message is received.
	// Arguments:
	//	 peer - peer
	//	 roomType - type of room
	//	 pNick - nick of sender
	//	 pMessage - message text
	//	 messageType - type of message
	//	 pParam - user data
	static void PeerRoomMessageCallback( PEER peer, RoomType roomType, const gsi_char* pNick, const gsi_char* pMessage, MessageType messageType, void* pParam );

	// Description:
	//	 Called when an under-the-table message has arrived in a room the developer is in.
	// Arguments:
	//	 peer - peer
	//	 roomType - type of room
	//	 pNick - nick of sender
	//	 pCommand - command type of this UTM
	//	 pParameters - payload or content of this UTM
	//	 authenticated - true if this has been authenticated by the server
	//	 pParam - user data
	static void PeerRoomUTMCallback( PEER peer, RoomType roomType, const gsi_char* pNick, const gsi_char* pCommand, const gsi_char* pParameters, PEERBool authenticated, void* pParam );

	// Description:
	//	 Called when the name of a room the developer is in has changed.
	// Arguments:
	//	 peer - peer
	//	 roomType - type of room
	//	 pParam - user data
	static void PeerRoomNameChangedCallback( PEER peer, RoomType roomType, void* pParam );

	// Description:
	//	 Called when the name of a room the developer is in has changed.
	// Arguments:
	//	 peer - peer
	//	 roomType - type of room
	//	 pMode - current mode for this room
	//	 pParam - user data
	static void PeerRoomModeChangedCallback( PEER peer, RoomType roomType, CHATChannelMode* pMode, void* pParam );

	// Description:
	//	 Called when the name of a room the developer is in has changed.
	// Arguments:
	//	 peer - peer
	//	 pNick - nick of sender
	//	 pMessage - message text
	//	 messageType - type of message
	//	 pParam - user data
	static void PeerPlayerMessageCallback( PEER peer, const gsi_char* pNick, const gsi_char* pMessage, MessageType messageType, void* pParam );

	// Description:
	//	 Called when an under-the-table message has arrived from another player.
	// Arguments:
	//	 peer - peer
	//	 pNick - nick of sender
	//	 pCommand - command type of this UTM
	//	 pParameters - payload or content of this UTM
	//	 authenticated - true if this has been authenticated by the server
	//	 pParam - user data
	static void PeerPlayerUTMCallback( PEER peer, const gsi_char* pNick, const gsi_char* pCommand, const gsi_char* pParameters, PEERBool authenticated, void* pParam );

	// Description:
	//	 Called when another player in the same staging room as the user, has changed his ready status
	// Arguments:
	//	 peer - peer
	//	 pNick - nick of the player who's ready state changed
	//	 ready - player's new ready state
	//	 pParam - user data
	static void PeerReadyChangedCallback( PEER peer, const gsi_char* pNick, PEERBool ready, void* pParam );

	// Description:
	//	 Called when the host in the staging room launches the game
	// Arguments:
	//	 peer - peer
	//	 server - server object representing this host
	//	 pMessage - message that was passed into peerStartGame
	//	 pParam - user data
	static void PeerGameStartedCallback( PEER peer, SBServer server, const gsi_char* pMessage, void* pParam );

	// Description:
	//	 Called when a player has joined one of the rooms the local player has joined
	// Arguments:
	//	 peer - peer
	//	 roomType - type of room
	//	 pNick - nick of the player who joined
	//	 pParam - user data
	static void PeerPlayerJoinedCallback( PEER peer, RoomType roomType, const gsi_char* pNick, void* pParam );

	// Description:
	//	 Called when a player has left one of the rooms the local player has joined
	// Arguments:
	//	 peer - peer
	//	 roomType - type of room
	//	 pNick - nick of the player who left
	//	 pReason - reason the player left
	//	 pParam - user data
	static void PeerPlayerLeftCallback( PEER peer, RoomType roomType, const gsi_char* pNick, const gsi_char* pReason, void* pParam );

	// Description:
	//	 Called when the local player has been kicked from a room
	// Arguments:
	//	 peer - peer
	//	 roomType - type of room
	//	 pNick - nick of the kicker
	//	 pReason - reason for kick
	//	 pParam - user data
	static void PeerKickedCallback( PEER peer, RoomType roomType, const gsi_char* pNick, const gsi_char* pReason, void* pParam );

	// Description:
	//	 Called when the entire player list has been updated
	// Arguments:
	//	 peer - peer
	//	 roomType - type of room
	//	 pParam - user data
	static void PeerNewPlayerListCallback( PEER peer, RoomType roomType, void* pParam );

	// Description:
	//	 Called when player in one of the rooms changed his nick
	// Arguments:
	//	 peer - peer
	//	 roomType - type of room
	//	 pOldNick - old nick
	//	 pNewNick - new nick
	//	 pParam - user data
	static void PeerPlayerChangedNickCallback( PEER peer, RoomType roomType, const gsi_char* pOldNick, const gsi_char* pNewNick, void* pParam );

	// Description:
	//	 Called for all players (who are using peer) in a room shortly after joining
	// Arguments:
	//	 peer - peer
	//	 roomType - room the info was gotten in
	//	 pNick - nick of the player the info is for
	//	 IP - player's IP
	//	 profileID - player's profile ID
	//	 pParam - user data
	static void PeerPlayerInfoCallback( PEER peer, RoomType roomType, const gsi_char* pNick, unsigned int IP, int profileID, void* pParam );

	// Description:
	//	 Called when a player's flags have changed
	// Arguments:
	//	 peer - peer
	//	 roomType - room the info was gotten in
	//	 pNick - nick of the player the info is for
	//	 oldFlags - player's old flags
	//	 newFlags - player's new flags
	//	 pParam - user data
	static void PeerPlayerFlagsChangedCallback( PEER peer, RoomType roomType, const gsi_char* pNick, int oldFlags, int newFlags, void* pParam );

	// Description:
	//	 Called when updated ping time is received.
	// Arguments:
	//	 peer - peer
	//	 pNick - nick of the player the info is for
	//	 ping - ping
	//	 pParam - user data
	static void PeerPingCallback( PEER peer, const gsi_char* pNick, int ping, void* pParam );

	// Description:
	//	 Called when updated cross-ping time is received.
	// Arguments:
	//	 peer - peer
	//	 pNick1 - first player's nick
	//	 pNick2 - second player's nick
	//	 crossPing - cross-ping
	//	 pParam - user data
	static void PeerCrossPingCallback( PEER peer, const gsi_char* pNick1, const gsi_char* pNick2, int crossPing, void* pParam );

	// Description:
	//	 Called when a global watch key changes value
	// Arguments:
	//	 peer - peer
	//	 pNick - player's nick
	//	 pKey - key
	//	 pValue - value
	//	 pParam - user data
	static void PeerGlobalKeyChangedCallback( PEER peer, const gsi_char* pNnick, const gsi_char* pKey, const gsi_char* pValue, void* pParam );

	// Description:
	//	 Called when a room watch key or a broadcast key changes value
	// Arguments:
	//	 peer - peer
	//	 roomType - room the info was gotten in
	//	 pNick - player's nick
	//	 pKey - key
	//	 pValue - value
	//	 pParam - user data
	static void PeerRoomKeyChangedCallback( PEER peer, RoomType roomType, const gsi_char* pNick, const gsi_char* pKey, const gsi_char* pValue, void* pParam );

#if !defined(PURE_CLIENT)
	// Description:
	//	 Called while you are hosting a game for you to report a game
	//	 host key value, such as the name of the map being played
	// Arguments:
	//	 peer - peer
	//	 key - key for which to report information
	//	 buffer - fill in the information using this buffer
	//	 pParam - user data
	static void PeerQRServerKeyCallback( PEER peer, int key, qr2_buffer_t buffer, void* pParam );

	// Description:
	//	 Called while you are hosting a game for you to report the
	//	 values of your player keys
	// Arguments:
	//	 peer - peer
	//	 key - key for which to report information
	//	 index - index of the player for which to report info
	//	 buffer - fill in the information using this buffer
	//	 pParam - user data
	static void PeerQRPlayerKeyCallback( PEER peer, int key, int index, qr2_buffer_t buffer, void* pParam );

	// Description:
	//	 Called while you are hosting a game for you to report the values of
	//	 your team keys
	// Arguments:
	//	 peer - peer
	//	 key - key for which to report information
	//	 index - index of the team for which to report info
	//	 buffer - fill in the information using this buffer
	//	 pParam - user data
	static void PeerQRTeamKeyCallback( PEER peer, int key, int index, qr2_buffer_t buffer, void* pParam );

	// Description:
	//	 Called while you are hosting a game for you to report the list of game
	//	 host keys you intend to provide
	// Arguments:
	//	 peer - peer
	//	 type - type of keys being asked for (key_server, key_player, or key_team)
	//	 keyBuffer - fill in the keys using this buffer
	//	 pParam - user data
	static void PeerQRKeyListCallback( PEER peer, qr2_key_type type, qr2_keybuffer_t keyBuffer, void* pParam );

	// Description:
	//	 Called while you are hosting a game for you to report the number of
	//	 players or teams you are hosting
	// Arguments:
	//	 peer - peer
	//	 type - type of count to return (key_player or key_team)
	//	 pParam - user data
	// Return:
	//	 Number of players or teams.
	static int PeerQRCountCallback( PEER peer, qr2_key_type type, void* pParam );

	// Description:
	//	 Called when you are hosting a game if there was an error getting your
	//	 game host published to the list
	// Arguments:
	//	 peer - peer
	//	 qr2_error_t - type of error
	//	 pErrorString - text string containing the error
	//	 pParam - user data
	static void PeerQRAddErrorCallback( PEER peer, qr2_error_t error, gsi_char* pErrorString, void* pParam );
#endif // !defined(PURE_CLIENT)

	static void NATNegotiateProgressCallback(NegotiateState state, void* pUserData);
	static void NATNegotiateCompletedCallback(NegotiateResult result, SOCKET gamesocket, struct sockaddr_in *pRemoteAddr, void *pUserData);

	// Description:
	//	 Called while you are hosting a game when a NAT-negotiation cookie is
	//	 received from a client that would like to NAT negotiate to connect with
	//	 you
	// Arguments:
	//	 peer - peer
	//	 cookie - cookie sent from a potential client
	//	 pParam - user data
	static void PeerQRNatNegotiateCallback( PEER peer, int cookie, void* pParam );

	// Description:
	//	 Called when you are hosting a game to report your publicly visible IP
	//	 address to you
	// Arguments:
	//	 peer - peer
	//	 ip - public reporting IP
	//	 port - public reporting port
	//	 pParam - user data
	static void PeerQRPublicAddressCallback( PEER peer, unsigned int ip, unsigned short port, void* pParam );

	// Description:
	//	 Called when an error occurs while selecting a nick.
	// Arguments:
	//	 peer - peer
	//	 type - type of error
	//	 pNick - bad nick
	//	 numSuggestedNicks - number of suggested nicks
	//	 ppSuggestedNicks - suggested nicks
	//	 pParam - user data
	static void PeerNickErrorCallback( PEER peer, int type, const gsi_char* pNick, int numSuggestedNicks, const gsi_char** ppSuggestedNicks, void* pParam );

	// Description:
	//	 Called when a peerConnect completes.
	// Arguments:
	//	 peer - peer
	//	 success - did the peerConnect succeed?
	//	 failureReason - reason for failure
	//	 pParam - user data
	static void PeerConnectCallback( PEER peer, PEERBool success, int failureReason, void* pParam );

	// Description:
	//	 Called when a peerListGroupRooms completes.
	// Arguments:
	//	 peer - peer
	//	 success - was the peerListGroupRooms successful
	//	 groupID - group ID
	//	 server - server
	//	 pName - name
	//	 numWaiting - number of players in room.
	//	 maxWaiting - maximum number of players in room.
	//	 numGames - number of games in the group
	//	 numPlaying - number of players in games in the group
	//	 pParam - user data
	static void PeerListGroupRoomsCallback( PEER peer, PEERBool success, int groupID, SBServer server, const gsi_char* pName, int numWaiting, int maxWaiting, int numGames, int numPlaying, void* pParam );

	// Description:
	//	 Called when a peerJoin*Room complets.
	// Arguments:
	//	 peer - peer
	//	 success - was the peerListGroupRooms successful
	//	 result - result
	//	 roomType - room type
	//	 pParam - user data
	static void PeerJoinRoomCallback( PEER peer, PEERBool success, PEERJoinResult result, RoomType roomType, void* pParam );

	static void GPErrorCallback( GPConnection* pGPConnection, void* pArg, void* pUserData );

	void StartGameSpyAvailabilityCheck();

	void WaitForGameSpyAvailabilityCheck();

	void SetNeedGameSpyObject( EGameSpyObjectBit object, bool state );

	void DispatchOnlineStatus( ECryLobbySystemEvent event, EOnlineState state, ECryLobbyError reason );
	void DispatchNickRejected( uint32 numNicks, char** ppNicks, bool disconnect, ECryLobbyError reason );
	void SetGameSpyObjectState( EGameSpyObject object, ECryGameSpyObjectState state, ECryLobbyError reason );
	void TickRoomOps();
	void GetNextRoomOp();
	void StartRoomOp();
	void CancelRoomOp();
	void StartCreateRoom();
	void StartJoinRoom();
	void StartLeaveRoom();
	static void PeerCreateStagingRoomCallback( PEER peer, PEERBool success, PEERJoinResult result, RoomType roomType, void* pParam );
	ECryLobbyLoginGUIState GetLoginCredentials();

	void AuthServiceStartLogin();
	static void AuthServiceWSLoginCallback( GHTTPResult httpResult, WSLoginResponse * response, void * userData );

	static void NATDetectionCallback( gsi_bool success, NAT nat );
	void DispatchNATType();

	void ClearSignedInDetails();

	CWorkQueue										m_workQueue;
	int64													m_connectionWaitTime;

	char													m_loginTicket[GP_LOGIN_TICKET_LEN];

	ECryGameSpyObjectState				m_states[ eGSO_Num ];
	uint32												m_neededGameSpyObjects;

	PEER													m_peer;
	PEERCallbacks									m_peerCallbacks;
	bool													m_peerSearching;

	bool													m_havePublicAddress;
	int														m_peerPublicIP;
	short													m_peerPublicPort;

	GPConnection									m_GPConnection;

	CryFixedStringT<GAMESPY_MAX_TITLE_LEN>	m_title; 
	CryFixedStringT<GAMESPY_MAX_SECRET_KEY_LEN>	m_secretKey;
	CryFixedStringT<GP_NICK_LEN>						m_requiredNick;
	CryFixedStringT<GAMESPY_MAX_VERSION_STRING_LEN>	m_gameVersionString;
	uint32																	m_distributionID;
	uint32																	m_namespaceID;
	uint32																	m_productID;
	uint32																	m_partnerID;
	uint32																	m_gameID;
	uint32																	m_gameVersion;

	int32																m_bestProfileQuality;
	CryFixedStringT<GP_NICK_LEN>				m_bestProfileNick;
	CryFixedStringT<GP_UNIQUENICK_LEN>	m_bestProfileUniqueNick;

	CryFixedStringT<GP_EMAIL_LEN>				m_email;
	CryFixedStringT<GP_NICK_LEN>				m_nick;
	CryFixedStringT<GP_UNIQUENICK_LEN>	m_uniqueNick;
	CryFixedStringT<GP_PASSWORD_LEN>		m_password;
	CryFixedStringT<GP_CDKEY_LEN>				m_cdKey;
	uint32															m_loginCount;
	bool																m_requireNewCredentials;
	bool																m_usingCDKey;

	GPEnum																	m_targetGPStatus;
	CryFixedStringT<GP_STATUS_STRING_LEN>		m_targetGPStatusString;
	CryFixedStringT<GP_LOCATION_STRING_LEN>	m_targetGPLocationString;
	GPEnum																	m_reportedGPStatus;
	CryFixedStringT<GP_STATUS_STRING_LEN>		m_reportedGPStatusString;
	CryFixedStringT<GP_LOCATION_STRING_LEN>	m_reportedGPLocationString;
	bool																		m_GPStatusDirty;

	_smart_ptr<CCryGameSpyMatchMaking>				m_pMatchMaking;
#if USE_CRYLOBBY_GAMESPY_VOIP
	_smart_ptr<CCryGameSpyVoice>							m_pVoice;
#endif
	_smart_ptr<CCryGameSpyStats>							m_pStats;
	_smart_ptr<CCryGameSpyFriends>						m_pFriends;
	_smart_ptr<CCryGameSpyFriendsManagement>	m_pFriendsManagement;
	_smart_ptr<CCryGameSpyLobbyUI>						m_pLobbyUI;
	_smart_ptr<CCryGameSpyDLCStore>						m_pDLCStore;

	std::queue<SRoomOpPtr>				m_roomOpQueue;
	SRoomOpPtr										m_pCurrentRoomOp;

	ERoomJoinState								m_roomJoinState[ NumRooms ];
	ETaskState										m_groupRoomRefreshState;
	std::vector<SGroupRoom>				m_groupRooms;
	int														m_initialised;
	GPProfile											m_profileId;
	GSLoginCertificate						m_authServiceCertificate;  // Show this to others (prooves: "Bill is a valid user")
	GSLoginPrivateData						m_authServicePrivateData;  // Keep this secret!   (prooves: "I am Bill")
	EReportingState								m_reportingState;

	static ENatType								s_NATType;
	static ENATDetectionState			s_NATDetectionState;

public:
#if USE_CRYLOBBY_GAMESPY_VOIP
	// GameSpy VOIP console vars
	int														net_gamespy_voip_enable;
	int														net_gamespy_voip_loopback;
	int														net_gamespy_voip_logging;
	float													net_gamespy_voip_threshold;
	int														net_gamespy_voip_ptt;
	float													net_gamespy_voip_playback_volume;
#endif
};

#endif // USE_CRYLOBBY_GAMESPY
#endif // __CRYGAMESPYLOBBY_H__
